using System;
using System.Collections;
using System.Text;
using Noea.TogSim.Model.Interfaces;

namespace Noea.TogSim.Model.Tracks
{
    public class SimpleTrack : ITrack
    {
        int _id;
        bool _blocked;
        double _length;
        double _angle;
        ITrack _nextTrack;
        ITrack _previousTrack;
        ITrainSet _train;
        ArrayList _signals;
        ArrayList _sensors;


        public SimpleTrack(int id)
        {
            Init(id, false, 0, 0, null, null, null, null);
        }
        public SimpleTrack(int id, bool blocked)
        {
            Init(id, blocked, 0, 0, null, null, null, null);
        }
        public SimpleTrack(int id, bool blocked, double length)
        {
            Init(id, blocked, length, 0, null, null, null, null);
        }
        public SimpleTrack(int id, bool blocked, double length, ITrack next, ITrack prev)
        {
            Init(id, blocked, length, 0, next, prev, null, null);
        }
        public SimpleTrack(int id, bool blocked, double length, double angle, ITrack next, ITrack prev)
        {
            Init(id, blocked, length, angle, next, prev, null, null);
        }
        public SimpleTrack(int id, bool blocked, double length, double angle, ITrack next, ITrack prev, ISignal sig)
        {
            Init(id, blocked, length, angle, next, prev, sig, null);
        }
        private void Init(int id, bool blocked, double length, double angle, ITrack next, ITrack prev, ISignal sig, ISensor sensor)
        {
            _id = id;
            _blocked = blocked;
            _length = length;
            _angle = angle;
            _nextTrack = next;
            _previousTrack = prev;
            _train = null;
            _signals = new ArrayList();
            _sensors = new ArrayList();
            if (sig != null) Signals.Add(sig);
            if (sensor != null) Sensors.Add(sensor);
        }

        #region ITrack Members

        public event BlockHandler OnBlock;
        public event TrackChangeHandler OnChange;

        public int Id { get { return _id; } }
        public double Length { get { return _length; } set { _length = value; } }
        public double Angle { get { return _angle; } set { _angle = value; } }
        public virtual ITrack Next { get { return _nextTrack; } set { _nextTrack = value; } }
        public virtual ITrack Previous { get { return _previousTrack; } set { _previousTrack = value; } }
        public virtual ITrack[] NextList { get { ITrack[] a = { Next }; return a; } }
        public ITrack[] PreviousList { get { ITrack[] a = { Previous }; return a; } }
        public ITrainSet Train { get { return _train; } set { _train = value; } }
        public IList Signals { get { return _signals; } }
        public IList Sensors { get { return _sensors; } }
        public void AddSignal(ISignal s) { Signals.Add(s); }
        public void RemoveSignal(ISignal s) { Signals.Remove(s); }
        public bool IsBlocked { get { return _blocked; }
            set
            {
                bool newValue = (Boolean)value;
                bool oldValue = _blocked;
                if (oldValue != newValue)
                {
                    _blocked = newValue;
                    BlockHandler tempBlockEvent = OnBlock;
                    if (tempBlockEvent != null)
                    {
                        ITrackEventArgs args = new TrackEventArgs(this, oldValue, newValue);
                        tempBlockEvent(this, args);
                    }
                    foreach (ISensor s in Sensors)
                    {
                        if (s is SwitchSensor) s.Value = newValue;
                    }
                    FireChange(oldValue, newValue);
                }
            }
        }

        protected void FireChange(Object oldValue, Object newValue)
        {
            TrackChangeHandler tempChangeEvent = OnChange;
            if (tempChangeEvent != null)
            {
                ITrackEventArgs args = new TrackEventArgs(this, oldValue, newValue);
                tempChangeEvent(this, args);
            }
        }

        public virtual ITrack GetNext(ITrack previousTrack)
        {
            //if (previousTrack == null)
            //{
            //    if (this.Next != null) return this.Next;
            //    return this.Previous;
            //}
            if (previousTrack == null || this.Previous.Equals(previousTrack))
            {
                return this.Next;
            }
            else
            {
                return this.Previous;
            }
        }

        public void RemoveSignal(int index)
        {
            Signals.RemoveAt(index);
        }

        public ISignal GetSignal(int index)
        {
            return (ISignal)Signals[index];
        }

        public override string ToString()
        {
            return String.Format("Id: {0}, Next: {1}, Previous: {2}"
                , this.Id, (this.Next != null) ? this.Next.Id.ToString() : "NaN", (this.Previous != null) ? this.Previous.Id.ToString() : "NaN");
        }
        
        #endregion
    }
    
    public class TrackEventArgs : ITrackEventArgs
    {
        #region ITrackEventArgs Members

        ITrack _track;
        Object _oldValue;
        Object _newValue;

        public TrackEventArgs(ITrack t, object oldv, object newv)
        {
            _track = t;
            _oldValue = oldv;
            _newValue = newv;
        }

        public ITrack Track { get { return _track; } }
        public object OldValue { get { return _oldValue; } }
        public object NewValue { get { return _newValue; } }

        #endregion
    }
    
}
